using imitateMacQQ.WebApi.Configures;
using imitateMacQQ.WebApi.Domain.Friend.module.Entity;
using imitateMacQQ.WebApi.Domain.Friend.module.Entity.dao;
using imitateMacQQ.WebApi.Domain.Friend.module.Entity.dto;
using imitateMacQQ.WebApi.Domain.Friend.module.Interface;
using imitateMacQQ.WebApi.Domain.Friend.module.utils;
using imitateMacQQ.WebApi.Domain.Request.utils;
using imitateMacQQ.WebApi.Repository.EFCore.Model;
using Microsoft.EntityFrameworkCore;

namespace imitateMacQQ.WebApi.Domain.Friend.module.Service;

public class FriendService : IFriend
{
    public Request<Entity.Friend[]> GetFriendList(string accountSelf)
    {
        using var db = new DataDbContext();
        var list = db.Buddies.Where(e =>
            (e.RequestAccount == accountSelf || e.ResultAccount == accountSelf)
            && e.IsUsing == 1
        );
        var tempUsers = new List<string>();
        list.ForEachAsync(e =>
        {
            tempUsers.Add(e.RequestAccount ?? "NULL");
            tempUsers.Add(e.ResultAccount ?? "NULL");
        });
        var distinctItems = tempUsers
            .GroupBy(x => x).Select(y => y.First());
        var enumerable = distinctItems as string[] ?? distinctItems.ToArray();
        var res = new Entity.Friend[enumerable.Length];
        foreach (var item in enumerable)
        {
            var userName = GetUserName(item);
            var index = enumerable.FindIndex(item);
            res[index] = new Entity.Friend()
            {
                UserName = userName,
                Account = item
            };
        }

        return Request<Entity.Friend[]>.Ok(res);
    }

    private readonly INLogHelper _logHelper;

    public FriendService(INLogHelper logHelper)
    {
        _logHelper = logHelper;
    }

    public async Task<Request<string[]>> GetFriendListStr(string accountSelf)
    {
        try
        {
            await using DataDbContext db = new DataDbContext();
            var info = db.Buddies.Where(e =>
                (e.RequestAccount == accountSelf || e.ResultAccount == accountSelf)
                && e.IsUsing == 1
            ).ToArray();
            var res = new string[info.Length + 1];
            res[0] = accountSelf;
            var index = 1;
            if (info.Length <= 0) return Request<string[]>.Ok(res);
            foreach (var item in info)
            {
                res[index] = item.RequestAccount == accountSelf
                    ? item.ResultAccount ?? "NULL"
                    : item.RequestAccount ?? "NULL";
                ++index;
            }

            return Request<string[]>.Ok(res);
        }
        catch (Exception ex)
        {
            _logHelper.LogError(ex);
            return Request<string[]>.Ok(null!, false, ex.Message);
        }
    }

    public Request<bool> AskFriendRelation(AskFriend friend)
    {
        try
        {
            if (string.IsNullOrEmpty(friend.Account1) || string.IsNullOrEmpty(friend.Account2)
               )
                return Request<bool>.Ok(false, false, "Account isNUll");
            if (friend.Account1 == friend.Account2)
                return Request<bool>.Ok(false);
            using var db = new DataDbContext();
            var info = db.Buddies.FirstOrDefault(e =>
                (e.RequestAccount == friend.Account1 && e.ResultAccount == friend.Account2) ||
                (e.RequestAccount == friend.Account2 && e.ResultAccount == friend.Account1)
            );
            if (info is not null)
                return Request<bool>.Ok(true);
            db.Buddies.Add(new Buddy()
            {
                RequestAccount = friend.Account1,
                ResultAccount = friend.Account2,
                IsUsing = 3
            });
            db.SaveChanges();
            return Request<bool>.Ok(true);
        }
        catch (Exception ex)
        {
            _logHelper.LogError(ex);
            return Request<bool>.Ok(false, false, ex.Message);
        }
    }

    public Request<bool> AskResult(AskFriendResult dto)
    {
        try
        {
            using var db = new DataDbContext();
            var askRelation = db.Buddies.First(e =>
                e.RequestAccount == dto.Account1 && e.ResultAccount == dto.Account2);
            askRelation.IsUsing = dto.IsUsing;
            db.SaveChanges();
            return Request<bool>.Ok(true);
        }
        catch (Exception ex)
        {
            _logHelper.LogError(ex);
            return Request<bool>.Ok(false, false, ex.Message);
        }
    }

    public async Task<Request<bool>> AskRelation(Relation dto)
    {
        try
        {
            if (string.IsNullOrEmpty(dto.AcceptAccount) || string.IsNullOrEmpty(dto.SendAccount))
                return Request<bool>.Ok(false, false, "Data Is Null");
            if (dto.SendAccount == dto.AcceptAccount)
                return Request<bool>.Ok(true);
            await using var db = new DataDbContext();
            var info = await db.Buddies.FirstOrDefaultAsync(e =>
                (e.RequestAccount == dto.SendAccount && e.ResultAccount == dto.AcceptAccount)
                || (e.RequestAccount == dto.AcceptAccount && e.ResultAccount == dto.SendAccount));
            return info is null ? Request<bool>.Ok(false) : Request<bool>.Ok(info.IsUsing == 1);
        }
        catch (Exception ex)
        {
            _logHelper.LogError(ex);
            return Request<bool>.Ok(false, false, ex.Message);
        }
    }

    public async Task<Request<RequestList[]>> GetRequestList(string dto)
    {
        try
        {
            if (string.IsNullOrEmpty(dto))
                return Request<RequestList[]>.Ok(null!, false, "User Is NUll");
            await using DataDbContext db = new DataDbContext();
            var info = db.Buddies.Where(
                e => e.ResultAccount == dto && e.IsUsing != 1).ToList();
            if (info.Count < 1)
                return Request<RequestList[]>.Ok(null!);
            var res = new RequestList[info.Count];
            var index = 0;
            foreach (var item in info)
            {
                var temp = db.Users.First(e => e.Account == item.RequestAccount);
                res[index] = new RequestList()
                {
                    Account = item.RequestAccount,
                    Header = temp.Header,
                    Name = temp.UserName,
                    State = item.IsUsing,
                };
                ++index;
            }

            return Request<RequestList[]>.Ok(res);
        }
        catch (Exception ex)
        {
            _logHelper.LogError(ex);
            return Request<RequestList[]>.Ok(null!, false, ex.Message);
        }
    }

    private string GetUserName(string account)
    {
        using DataDbContext db = new DataDbContext();
        var res = db.Users.First(e => e.UserName == account);
        return res.UserName ?? "NULL";
    }
}